package ch.sfug.display {
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	
	import ch.sfug.events.SliderEvent;		

	public class Slider extends Sprite {

		private var _thumb:Sprite;
		private var _bg:Sprite;

		private var dy_mouse:Number;
		private var _scalable:Boolean = false;
		protected var _snap:Boolean = false;
		protected var step:Number = 5;

		public function Slider() {
			super();

			if( _thumb == null) {
				var default_thumb:Sprite = new Sprite();
				default_thumb.graphics.beginFill(0xeeeeee);
				default_thumb.graphics.drawRect(0, 0, 10, 80);
				default_thumb.graphics.endFill();
				thumb = default_thumb;
			}
			
			if( _bg == null) {
				var default_bg:Sprite = new Sprite();
				default_bg.graphics.beginFill(0xeeeeee);
				default_bg.graphics.drawRect(0, 0, 10, 80);
				default_bg.graphics.endFill();
				bg = default_bg;
			}

		}

		public override function set width( w:Number ):void {
			_thumb.width = w;
			_bg.width = w;
		}

		public override function set height( h:Number ):void {
			
			var pos:Number = position;
			var size:Number = _thumb.height / _bg.height;
			
			_thumb.y = 0;
			_bg.height = h;
			
			position = pos;
			if( _scalable ) scaleThumb(size);
		}

		
		public function get position():Number {
			var p:Number = ( _thumb.y - _bg.y ) / ( _bg.height - _thumb.height );
			return Math.max(Math.min(p, 1), 0);
		}

		public function set position( p:Number ):void {
			_thumb.y = _bg.y + ( _bg.height - _thumb.height ) * Math.min(Math.max(p, 0), 1);
		}

		/**
		 * sets the thumb size in the given ratio r.
		 */

		public function scaleThumb( r:Number ):void {
			
			if(isNaN(r) || r > 1 || r < 0) throw new Error("scale thumb ratio must a be number between 0 and 1 : not " + r);
			
			_scalable = true;
			var p:Number = position;
			_thumb.height = r * _bg.height;
			_thumb.visible = ( r < 1 );
			position = p;
		}

		/**
		 * sets the number of steps for the arrow
		 */
		public function set steps( num:uint ):void {
			step = Math.max(1, num);
		}

		public function get steps():uint {
			return step;
		}

		/**
		 * returns the current step number. if you have slider.steps = 5 you will get values from 0 to 4. 
		 */
		public function get currentStep():uint {
			return Math.round(position * ( steps - 1 ));
		}

		
		/**
		 * sets the number of steps it needs with the arrow 
		 */
		public function set snap( b:Boolean ):void {
			_snap = b;
		}

		
		public function stepsUp( val:Number = 1 ):void {
			position -= val / ( step - 1 );
			dispatchEvent(new SliderEvent(SliderEvent.STEP));
			dispatchEvent(new SliderEvent(SliderEvent.MOVE));
		} 

		public function stepsDown( val:Number = 1 ):void {
			position += val / ( step - 1 );
			dispatchEvent(new SliderEvent(SliderEvent.STEP));
			dispatchEvent(new SliderEvent(SliderEvent.MOVE));
		} 

		protected function snapThumb():void {
			var pystep:Number = ( _bg.height - _thumb.height ) / ( step - 1 );
			_thumb.y = _bg.y + Math.round(( _thumb.y - _bg.y ) / pystep) * pystep;
			dispatchEvent(new SliderEvent(SliderEvent.SNAP));
		}

		protected function onTrackClicked( e:MouseEvent ):void {
			if(_bg.y + ( _bg.mouseY * _bg.scaleY ) < _thumb.y) {
				stepsUp();
			} else {
				stepsDown();
			}
		}

		protected function onThumbDown( e:MouseEvent ):void {
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onThumbMove);
			stage.addEventListener(MouseEvent.MOUSE_UP, onThumbUp);
			dy_mouse = _thumb.mouseY * _thumb.scaleY;
		} 

		
		protected function onThumbUp( e:MouseEvent ):void {
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, onThumbMove);
			stage.removeEventListener(MouseEvent.MOUSE_UP, onThumbUp);
			_thumb.y = Math.max(Math.min(_bg.y + ( _bg.mouseY * _bg.scaleY ) - dy_mouse, _bg.y + _bg.height - _thumb.height), _bg.y);
			if( _snap && step > 1 ) snapThumb();
			dispatchEvent(new SliderEvent(SliderEvent.MOVE));		
		}

		
		protected function onThumbMove( e:MouseEvent ):void {
			_thumb.y = Math.max(Math.min(_bg.y + ( _bg.mouseY * _bg.scaleY ) - dy_mouse, _bg.y + _bg.height - _thumb.height), _bg.y);
			dispatchEvent(new SliderEvent(SliderEvent.MOVE));
		}
		
		public function set thumb( t:Sprite ):void {
			if( _thumb != null ) {
				_thumb.removeEventListener(MouseEvent.MOUSE_DOWN, onThumbDown);
				removeChild( _thumb );
			}
			_thumb = t;
			if( !contains( _thumb ) ) addChild( _thumb );
			_thumb.addEventListener( MouseEvent.MOUSE_DOWN, onThumbDown);
		}
		
		
		public function set bg( t:Sprite ):void {
			if( _bg != null ) {
				_bg.removeEventListener( MouseEvent.CLICK, onTrackClicked );
				removeChild( _bg );
			}
				
			_bg = t;
			if( !contains( _bg ) ) addChild( _bg );
			_bg.addEventListener(MouseEvent.CLICK, onTrackClicked);
		}
	}
}